#include"flvapi.h"
int FlvCheckHead(FILE*fp){
	uint32_t filetype=0;
	//uint32_t typeflv='FLV';
        uint32_t typeflv=MAKETYPE('F','L','V','\0');
	if(ReadU24(&filetype,fp)<0)return -1;
	if(filetype!=typeflv){
	   printf("Not FLV File\n");
	   return -1;
	}
	fseek(fp,1,SEEK_CUR);
	filetype=0;
	if (ReadU8(&filetype,fp)<0)return -1;
	if (filetype&FLV_FLAG_VIDEO){
		printf("Has Video\n");
	}
	if (filetype&FLV_FLAG_AUDIO){
		printf("Has Audio\n");
	}
	fseek(fp,13,SEEK_SET);
	return 0;
}
int FlvGetNextFrame(FILE*fp,flvframe*frameinfo){
	//type
	if (ReadU8(&frameinfo->type,fp)<0)return -1;		
	//datalength
	if (ReadU24(&frameinfo->datalength,fp)<0)return -1;		
	//timestamp
	if (ReadTime(&frameinfo->timestamp,fp)<0)return -1;
	//pass StreamID/////
	fseek(fp,3,SEEK_CUR);
	//try read firstbyte
	if(PeekU8(&frameinfo->info,fp)<0)return -1;
	frameinfo->datapos=ftell(fp);
	return 0;
}

int FlvWriteHead(FILE*fp,int flag){
	//uint32_t typeflv='FLV';
        uint32_t typeflv=MAKETYPE('F','L','V','\0');
	if (WriteU24(typeflv,fp)<0)return -1;
	if (WriteU8(1,fp)<0)return -1;
	if (WriteU8(flag,fp)<0)return -1;
	if (WriteU32(9,fp)<0)return -1;
	if (WriteU32(0,fp)<0)return -1;
	return 0;
}
int FlvWriteFrame(FILE*fp,flvframe*frameinfo,const char*data){
	//type
	if (WriteU8(frameinfo->type,fp)<0)return -1;		
	//datalength
	if (WriteU24(frameinfo->datalength,fp)<0)return -1;		
	//timestamp
	if (WriteTime(frameinfo->timestamp,fp)<0)return -1;
	//StreamID//
	if (WriteU24(0,fp)<0)return -1;
	if (fwrite(data,1,frameinfo->datalength,fp)!=frameinfo->datalength)return -1;
	if (WriteU32(frameinfo->datalength+11,fp)<0)return -1;
	return 0;
}

int FlvWriteFAACInfo(FILE*flvfile,ADSTHEADINFO Info,uint32_t timestamp){
	uint8_t buff[2]={0};
	uint32_t datalen=2+2;
	buff[0]=(((Info.profile+1)<<3)&0xF8)|((Info.sr_idx&0x0E)>>1);
	buff[1]=((Info.sr_idx<<7)&0x80)|((Info.nb_ch<<3)&0x78);
	
	WriteU8(8,flvfile);
	WriteU24(datalen,flvfile);
	WriteTime(timestamp,flvfile);
	WriteU24(0,flvfile);

	
	WriteU8(0xAF,flvfile);
	WriteU8(0x00,flvfile);

	fwrite(buff,1,2,flvfile);

	WriteU32(datalen+11,flvfile);
	return 0;
}

int FlvWriteFAACInfoFrame(FILE*flvfile,uint8_t*buffer,uint32_t buffersize,uint32_t timestamp){
	uint32_t datalen=buffersize+2;
	WriteU8(8,flvfile);
	WriteU24(datalen,flvfile);
	WriteTime(timestamp,flvfile);
	WriteU24(0,flvfile);
	
	WriteU8(0xAF,flvfile);
	WriteU8(0x00,flvfile);

	fwrite(buffer,1,buffersize,flvfile);

	WriteU32(datalen+11,flvfile);
	return 0;
}

int FlvWriteFAACFrame(FILE*flvfile,uint8_t*buffer,uint32_t buffersize,uint32_t timestamp){
	uint32_t datalen=buffersize+2;
	WriteU8(8,flvfile);
	WriteU24(datalen,flvfile);
	WriteTime(timestamp,flvfile);
	WriteU24(0,flvfile);
	
	WriteU8(0xAF,flvfile);
	WriteU8(0x01,flvfile);

	fwrite(buffer,1,buffersize,flvfile);

	WriteU32(datalen+11,flvfile);
	return 0;
}

int FlvWriteX264Info(FILE*flvfile,uint8_t*sps,uint32_t spssize,uint8_t*pps,uint32_t ppssize,uint32_t timestamp){
	uint32_t datalen=spssize+ppssize+16;
	WriteU8(9,flvfile);
	WriteU24(datalen,flvfile);
	WriteTime(timestamp,flvfile);
	WriteU24(0,flvfile);
		
	WriteU8(0x17,flvfile);
	WriteU8(0x00,flvfile);
	WriteU24(0,flvfile);

	WriteU8(0x01,flvfile);
	WriteU8(sps[1],flvfile);
	WriteU8(sps[2],flvfile);
	WriteU8(sps[3],flvfile);

	WriteU8(0x03,flvfile);
	WriteU8(0xE1,flvfile);

	WriteU16(spssize,flvfile);
	fwrite(sps,1,spssize,flvfile);

	WriteU8(0x01,flvfile);
	WriteU16(ppssize,flvfile);
	fwrite(pps,1,ppssize,flvfile);
	
	WriteU32(datalen+11,flvfile);

	return 0;
//	printf("spssize:%u ppssize:%u\n",spssize,ppssize);

}
int FlvWriteX264Frame(FILE*flvfile,uint8_t*buffer,uint32_t buffersize,uint8_t bKeyFrame,uint32_t timestamp){
	uint32_t datalen=buffersize+9;
	WriteU8(9,flvfile);
	WriteU24(datalen,flvfile);
	WriteTime(timestamp,flvfile);
	WriteU24(0,flvfile);

	if(bKeyFrame)
		WriteU8(0x17,flvfile);
	else
		WriteU8(0x27,flvfile);
	WriteU8(0x01,flvfile);
	WriteU24(0,flvfile);

	WriteU32(buffersize,flvfile);
	fwrite(buffer,1,buffersize,flvfile);

	WriteU32(datalen+11,flvfile);
	return 0;
}

const char*FlvGetAudioInfo(int info){
	static char temp[256]={0};
	char buff[100]={0};
	int temptype=0;
	memset(temp,0,sizeof(temp));
	temptype=info>>4&0xf;
	switch (temptype){
	case 0:
		strcpy(temp,"0-LinearPCM,platform endian ");
		break;
	case 1:
		strcpy(temp,"1-ADPCM ");
		break;
	case 2:
		strcpy(temp,"2-MP3 ");
		break;
	case 3:
		strcpy(temp,"3-LinearPCM,little endian ");
		break;
	case 4:
		strcpy(temp,"4-Nellymoser 16kHz momo ");
		break;
	case 5:
		strcpy(temp,"5-Nellymoser 8kHz momo ");
		break;
	case 6:
		strcpy(temp,"6-Nellymoser ");
		break;
	case 7:
		strcpy(temp,"7-G.711 A-law logarithmic PCM ");
		break;
	case 8:
		strcpy(temp,"8-G.711 mu-law logarithmic PCM");
		break;
	case 10:
		strcpy(temp,"10-AAC ");
		break;
	case 11:
		strcpy(temp,"11-Speex ");
		break;
	case 14:
		strcpy(temp,"14-MP3 8kHz ");
		break;
	default:
		sprintf(buff,"UnKnow:%hd ",temptype);
		strcpy(temp,buff);
	}
    temptype=0;
	temptype=info>>2&0x3;
	switch (temptype){
	case 0:
		strcat(temp,"0-5.5kHz ");
		break;
	case 1:
		strcat(temp,"1-11kHz ");
		break;
	case 2:
		strcat(temp,"2-22kHz ");
		break;
	case 3:
		strcat(temp,"3-44kHz ");
		break;
	}
	temptype=0;
	temptype=info>>1&0x1;
	switch (temptype){
	case 0:
		strcat(temp,"0-8Bit ");
		break;
	case 1:
		strcat(temp,"1-16Bit ");
		break;
	}
	temptype=0;
	temptype=info&0x1;
	switch (temptype){
	case 0:
		strcat(temp,"0-Momo ");
		break;
	case 1:
		strcat(temp,"1-Stereo ");
		break;
	}
	return temp;
}
const char*FlvGetVideoInfo(int info){
	static char temp[256]={0};	
	char buff[100]={0};
	int temptype=0;
	memset(temp,0,sizeof(temp));
	temptype=info>>4&0xf;
	switch (temptype){
	case 1:
		strcpy(temp,"1-keyframe ");
		break;
	case 2:
		strcpy(temp,"2-inner frame ");
		break;
	case 3:
		strcpy(temp,"3-disposable inner frame (H.263 only) ");
		break;
	default:
		sprintf(buff,"UnKnow:%hd ",temptype);
		strcpy(temp,buff);
	}
	memset(buff,0,100);	
	temptype=0;
	temptype=info&0xf;
	switch (temptype){
	case 2:
		strcat(temp,"2-Seronson H.263 ");
		break;
	case 3:
		strcat(temp,"3-Screen video ");
		break;
	case 4:
		strcat(temp,"4-On2 VP6 ");
		break;
	case 5:
		strcat(temp,"5-On2 VP6 without channel ");
		break;
	case 6:
		strcat(temp,"6-Screen video version 2 ");
		break;
	case 7:
		strcat(temp,"7-H.264 ");
		break;
	default:
		sprintf(buff,"UnKnow:%hd ",temptype);
		strcat(temp,buff);
	}	
	return temp;
}

int WriteU8(uint32_t u8,FILE*f){
	 if(fwrite(&u8,1,1,f)!=1)return -1;
	 return 0;
}
int WriteU16(uint32_t u16,FILE*f){
	 u16=HTON16(u16);
	 if(fwrite(&u16,1,2,f)!=2)return -1;
	 return 0;
}
int WriteU24(uint32_t u24,FILE*f){
	 u24=HTON24(u24);
	 if(fwrite(&u24,1,3,f)!=3)return -1;
	 return 0;
}
int WriteU32(uint32_t u32,FILE*f){
	 u32=HTON32(u32);
	 if(fwrite(&u32,1,4,f)!=4)return -1;
	 return 0;
}
int WriteTime(uint32_t utime,FILE*f){
     utime=HTONTIME(utime);
	 if(fwrite(&utime,1,4,f)!=4)return -1;
	 return 0;
}
int PeekU8(uint32_t*u8,FILE*f){
	if(fread(u8,1,1,f)!=1)return -1;
	fseek(f,-1,SEEK_CUR);
	return 0;
}
int ReadU8(uint32_t*u8,FILE*f){
	 if(fread(u8,1,1,f)!=1)return -1;
	 return 0;
}
int ReadU16(uint32_t*u16,FILE*f){
	 if(fread(u16,1,2,f)!=2)return -1;
	 *u16=HTON16(*u16);
	 return 0;
}
int ReadU24(uint32_t*u24,FILE*f){
	 if(fread(u24,1,3,f)!=3)return -1;
	 *u24=HTON24(*u24);
	 return 0;
}
int ReadU32(uint32_t*u32,FILE*f){
	 if(fread(u32,1,4,f)!=4)return -1;
	 *u32=HTON32(*u32);
	 return 0;
}
int ReadTime(uint32_t*utime,FILE*f){
	 if(fread(utime,1,4,f)!=4)return -1;
	 *utime=HTONTIME(*utime);
	 return 0;
}
const char*ReadU8FromBuff(uint32_t*u8,const char*buff){
	memcpy(u8,buff,1);
	return buff+1;
}
const char*ReadU16FromBuff(uint32_t*u16,const char*buff){
	memcpy(u16,buff,2);
	*u16=HTON16(*u16);
	return buff+2;
}
const char*ReadU32FromBuff(uint32_t*u32,const char*buff){
	memcpy(u32,buff,4);
	*u32=HTON32(*u32);
	return buff+4;
}
const char*WriteBuff(FILE*fp,const char*buff,uint32_t len){
	fwrite(buff,1,len,fp);
	return buff+len;
}
char*WriteU16ToBuff(uint32_t u16,char*buff){
	 u16=HTON16(u16);
	 memcpy(buff,&u16,2);
	 return buff+2;
}
char*WriteU32ToBuff(uint32_t u32,char*buff){
	 u32=HTON32(u32);
	 memcpy(buff,&u32,4);
	 return buff+4;
}
//读取单个字节位置 0~7
int ReadBit(uint8_t data,int bit){
	int val=0;
	val=(data>>(7-bit))&0x01;
//	printf("data:0x%x bit:%d val:%d\n",data,bit,val);
	return val;
}
int ReadBitData(BitStream*info,int bits){
	int val=0;
	int lastpos=0;
	int lastbit=0;
	int b32bits=0;
	if(bits==32){
	   b32bits=1;
	   bits=40;
	}
	lastpos=info->pos+(info->bit+bits)/8;
	lastbit=(info->bit+bits)%8;
	if((lastpos>info->len)||((lastpos==info->len)&&(lastbit>0))){
	   printf("Total:%d Now Pos:%d Bit:%d Need:%d bits\n",info->len,info->pos,info->bit,bits);
	   return -1;
	}
//  bits为32时，改为40 中间 25~32忽略
//	printf("Total:%d Now Pos:%d Bit:%d Need:%d bits\n",info->len,info->pos,info->bit,bits);
	while(bits>0){
	  int tmp=ReadBit(info->data[info->pos],info->bit);
	  if((b32bits==1)&&(bits>8)&&(bits<17)){
//
	  }else{
	     val*=2;
	     val+=tmp;
	  }
	  info->bit++;
	  if(info->bit==8){
		 info->bit=0;
		 info->pos++;
	  }
	  bits--;
	}
//	printf("Total2:%d Now Pos:%d Bit:%d Need:%d bits\n",info->len,info->pos,info->bit,bits);
	if((info->pos!=lastpos)||(info->bit!=lastbit)){
//不应该有此错误
		printf("ReadBitData Error\n");
	}
	return val;
}

int ReadExData(BitStream*info){
	int count=-1;
	int val=0;	
	do{
	  val=ReadBitData(info,1);
	  count++;
	}while(val==0);
	if(val==-1){
	   return val;
	}
	val=1;
	while(count>0){
	   val*=2;
	   val+=ReadBitData(info,1);
	   count--;
	}
	return val-1;
}